template <typename A, typename B, class T>
struct Repr2 : T
{
  A fst;
  B snd;
  Repr2(A a, B b) : fst(a), snd(b)
  {
  }
  
};


template <class T, typename A, typename B>
Repr2<A, B, T> repr(void (T::*)(A, B));

template <class T>
T repr(void (T::*)(void));


struct Seed
{
  template <class U, typename T>
  struct Next : U
  {
    const T _;
    Next(const U& u, T _) : U(u), _(_) {}

    const U& __(void) const
    {
      return *this;
    }

    template <typename N>
    Next<Next, N> operator , (N n)
    {
      return Next<Next, N>(*this, n);
    }

    template <typename Z>
    void operator () (const Z& z)
    {
      // todo: invoke Z with *this
      //      static_cast<const Next&>(z.s);
      (z.s)(*this);
    }

    template <class V, typename S>
    Next(const Next<V, S>& n) : U(static_cast<U>(n.__())), _(static_cast<T>(n._))
    {
    }
  };

  template <typename T>
  Next<Seed, T> operator , (T t)
  {
    return Next<Seed, T>(*this, t);
  }
};


template <typename>
struct E
{
};

template <typename PARAM>
struct L
{
  template <typename>
  struct _ : L<PARAM>
  {
      // elimination functions
      void Nil(void);
      void Cons(PARAM, _&);
  };

  //  const Seed& s;
  void (*const s)(const Seed&);
};



template <template <typename> class F>
struct Rec : F< Rec<F> >
{
    typedef F< Rec<F> > __;
};


typedef Rec<E> Expr;
typedef Rec<L<int>::_> IntList;

// Type synonyms:
//   template <class T>
//   using MyVector = std::vector<T>;
//
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1489.pdf




struct Dispatch : IntList
{
  void Nil(void)
  {
  }
///  void Cons(int, IntList&)
//  void Cons(int, L<int>::_<Rec<L<int>::_> >&)
//  void Cons(int, _<Rec<_> >&)
//void Cons(int, _::_<Rec<_::_> >&)
  void Cons(int, __&)
  {
  }
};


int main(void)
{
  Expr e;
  IntList il;
  typeof(repr(&IntList::Nil)) ni;
  typeof(repr(&IntList::Cons)) co(42, co);
  typeof(repr(&IntList::Cons)) con(42, ni);

  (Seed(),&Dispatch::Nil,&Dispatch::Cons)(con);
  typeof(Seed(),&IntList::Nil) qq((Seed(),&Dispatch::Nil));
  typeof(Seed(),&IntList::Cons) qqq((Seed(),&Dispatch::Cons));
  typeof(Seed(),&IntList::Nil,&IntList::Cons) qqqq((Seed(),&Dispatch::Nil,&Dispatch::Cons));
  qqqq(con);
  //  con(qqqq);
  typeof(Seed(),&IntList::Nil,&IntList::Cons, &IntList::Nil) qqqqp((Seed(),&Dispatch::Nil,&Dispatch::Cons,&Dispatch::Nil));
  
  return con.fst;
}

